/*
 * color_clusterization.cpp
 *
 *  Created on: Dec 17, 2012
 *      Author: filipe mutz
 */
#include <opencv/cv.h>
#include <opencv/highgui.h>

#include "../../clustering/clustering_config.h"
#include "../../clustering/clustering_algorithms/kmeans.h"

char *input_image_name;
char *output_image_name;

IplImage *input_image;
IplImage *output_image;

double **points;
int *cluster_ids;

clustering_config config;


int
parse_args(int argc, char *argv[])
{
	if (argc < 3)
		return 0;

	input_image_name = argv[1];
	output_image_name= argv[2];

	return 1;
}


void
show_usage_information_and_exit(int argc, char *argv[])
{
	printf("\n");
	printf("Use %s <image-input> <image-output>\n", argv[0]);
	printf("\n");

	exit(-1);
}


void
read_image()
{
	input_image = cvLoadImage(input_image_name, CV_LOAD_IMAGE_COLOR);

	if (input_image == NULL)
		exit(printf("Error: '%s' could not be open\n", input_image_name));
}


void
allocate_points(double ***points_ptr, int num_points, int dimension)
{
	(*points_ptr) = (double **) calloc (num_points, sizeof(double *));

	for(int i = 0; i < num_points; i++)
		(*points_ptr)[i] = (double *) calloc (dimension, sizeof(double));
}


void
copy_image_pixel_color_to_points(double **points)
{
	for (int i = 0; i < input_image->height; i++)
	{
		for (int j = 0; j < input_image->width; j++)
		{
			int p = (i * input_image->widthStep + 3 * j);

			points[i * input_image->width + j][0] = (double) input_image->imageData[p + 0];
			points[i * input_image->width + j][1] = (double) input_image->imageData[p + 1];
			points[i * input_image->width + j][2] = (double) input_image->imageData[p + 2];
		}
	}
}


void
allocate_cluster_ids(clustering_config config, int **cluster_ids)
{
	(*cluster_ids) = (int *) calloc (config.num_points, sizeof(int));
}


void
generate_points_from_image_color(clustering_config config, double ***points_ptr)
{
	allocate_points(points_ptr, config.num_points, config.dimension);
	copy_image_pixel_color_to_points((*points_ptr));
}


void
apply_kmeans()
{
	config.dimension = 3;
	config.num_points = input_image->height * input_image->width;
	config.num_clusters = 6;

	allocate_cluster_ids(config, &cluster_ids);
	generate_points_from_image_color(config, &points);
	kmeans(config, points, cluster_ids);
}


unsigned char*
generate_color_table()
{
	unsigned char *color_table = (unsigned char *) calloc (config.num_clusters, sizeof(unsigned char));

	srand(time(NULL));

	for(int i = 0; i < config.num_clusters; i++)
	{
		double color = ((double) i / (double) config.num_clusters) * 255.0;
		color_table[i] = (unsigned char) (color);
	}

	return color_table;
}


void
create_output_image()
{
	unsigned char *color_table = generate_color_table();

	output_image = cvCreateImage(cvSize(input_image->width, input_image->height), input_image->depth, 1);

	for(int i = 0; i < input_image->height; i++)
		for(int j = 0; j < input_image->width; j++)
			output_image->imageData[i * output_image->widthStep + j] = color_table[cluster_ids[i * input_image->width + j]];
}


void
write_output_image_to_file()
{
	cvSaveImage(output_image_name, output_image);
}


int
main(int argc, char **argv)
{
	if (!parse_args(argc, argv))
		show_usage_information_and_exit(argc, argv);

	read_image();
	apply_kmeans();
	create_output_image();
	write_output_image_to_file();

	return 0;
}

